<template>
  <a-layout class="modeler" style="height: 100%">
    <a-layout class="app-containers-bpmn">
      <a-layout-header style="height: 40px; padding: 10px">
        <div style="display: flex; align-items: center; justify-content: space-between">
          <a-button-group>
            <a-tooltip content="重置视图并居中">
              <a-button @click="fitViewport">
                <template #icon>
                  <icon-drag-arrow />
                </template>
              </a-button>
            </a-tooltip>
            <a-tooltip content="缩小" @click="zoomViewport(false)">
              <a-button>
                <template #icon>
                  <icon-zoom-out />
                </template>
              </a-button>
            </a-tooltip>
            <a-tooltip content="放大" @click="zoomViewport(true)">
              <a-button>
                <template #icon>
                  <icon-zoom-in />
                </template>
              </a-button>
            </a-tooltip>
            <a-tooltip content="左移">
              <a-button @click="handleRight">
                <template #icon>
                  <icon-arrow-left />
                </template>
              </a-button>
            </a-tooltip>
            <a-tooltip content="右移">
              <a-button @click="handleLeft">
                <template #icon>
                  <icon-arrow-right />
                </template>
              </a-button>
            </a-tooltip>
          </a-button-group>
          <a-button-group>
            <a-button @click="handleSave">保存</a-button>
            <a-button>预览</a-button>
            <a-button>下载</a-button>
            <a-button @click="createNewDiagram">重新绘制</a-button>
          </a-button-group>
        </div>
      </a-layout-header>
      <a-layout-content>
        <div ref="canvas" class="canvas" />
      </a-layout-content>
    </a-layout>
    <a-layout-sider :collapsed="collapsed" :width="350" collapsible reverse-arrow @collapse="handleCollapse">
      <div v-show="!collapsed">
        <panel-info :bpmn-modeler="bpmnModeler" />
      </div>
    </a-layout-sider>
  </a-layout>
</template>
<script lang="ts" setup>
import "@/assets/bpmn/style/index.less";
import type { Canvas, Modeler } from "bpmn";
import "bpmn-js/dist/assets/diagram-js.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
import flowableModdle from "./assets/moddle/flowable";
import BpmnModeler from "bpmn-js/lib/Modeler.js";
import Module from "@/assets/bpmn/module";
import PanelInfo from "./panel/index.vue";
import { propTypes } from "@/utils/propTypes";

const canvas = ref<HTMLDivElement>();
const bpmnModeler = ref<Modeler | null>(null);
const panel = ref<HTMLDivElement>();
const collapsed = ref(false);
const value = ref("");
const zoom = ref<number>(1);

const props = defineProps({
  bpmnXml: propTypes.string.def(""),
  designerForm: propTypes.object.def({})
});

const initCanvas = () => {
  bpmnModeler.value = new BpmnModeler({
    container: canvas.value,
    // 键盘
    keyboard: {
      bindTo: window // 或者window，注意与外部表单的键盘监听事件是否冲突
    },
    propertiesPanel: {
      parent: panel.value
    },
    additionalModules: Module,
    moddleExtensions: {
      flowable: flowableModdle
    }
  });
  bpmnModeler.value.createDiagram();
};

const emit = defineEmits(["save"]);

const handleSave = () => {
  return new Promise((resolve, reject) => {
    if (bpmnModeler.value) {
      bpmnModeler.value.saveXML({ format: true }).then(({ xml }) => {
        emit("save", xml);
        resolve(xml);
      });
    } else {
      reject();
    }
  });
};

/**
 * 创建新的流程图
 */
const createNewDiagram = () => {
  bpmnModeler.value?.createDiagram();
};

const handleCollapse = (value: boolean, type: "clickTrigger" | "responsive") => {
  collapsed.value = value;
};

/**
 * 自适应屏幕
 */
const fitViewport = () => {
  // @ts-ignore
  bpmnModeler.value?.get<Canvas>("canvas").zoom("fit-viewport", "auto");
};

/**
 * 放大或者缩小
 * @param zoomIn true 放大 | false 缩小
 */
const zoomViewport = (zoomIn = true) => {
  // @ts-ignore
  zoom.value = bpmnModeler.value?.get<Canvas>("canvas").zoom();
  zoom.value += zoomIn ? 0.1 : -0.1;
  bpmnModeler.value?.get<Canvas>("canvas").zoom(zoom.value);
};

const handleRight = () => {
  // @ts-ignore
  bpmnModeler.value?.get("commandStack").undo();
};

const handleLeft = () => {
  // @ts-ignore
  bpmnModeler.value?.get("commandStack").redo();
};

onMounted(() => {
  nextTick(() => {
    initCanvas();
  });
});
</script>
<style lang="less" scoped>
.canvas {
  height: 100%;
  width: 100%;
}

.modeler {
  background: url("");
}
</style>
